import json
import socket
import socketserver

import yaml
import clr
import os, sys
import requests
import time
import HaloStart
from HaloStart import socket_value
import socketio

# 如果需要编译,在打开
sys.path.append(os.getcwd())

global http_url
global wss_url
sio = socketio.Client(reconnection=True, reconnection_attempts=0, reconnection_delay=5)

reconnect_delay = 2
connected = False
headers = {'Content-Type': 'application/json'}


class GetDeviceInfo:
    def __init__(self, dll: str):
        clr.AddReference(dll)
        from LibreHardwareMonitor.Hardware import Computer  # 在编译器里 这里有可能会报错 但是可以忽略他
        self.computer_tmp = Computer()  # 实例这这个类
        self.computer_tmp.IsCpuEnabled = True  # 获取CPU温度时用
        self.computer_tmp.IsGpuEnabled = True  # 获取GPU温度时用
        self.computer_tmp.IsMemoryEnabled = True  # 获取内存时用
        self.computer_tmp.IsNetworkEnabled = True  # 获取网卡时用
        # self.computer_tmp.IsMotherboardEnabled = True
        self.computer_tmp.Open()

    def params_hardware(self, index: int) -> dict:
        hard = self.computer_tmp.Hardware[index]
        hard.Update()
        device_data = {}
        clock_data = {}
        hardware_type = str(hard.HardwareType)
        # if 'MOTHERBOARD' in hardware_type.upper():
        #     for Sensor in hard.Sensors:
        #         sensor_type = str(Sensor.SensorType)
        #         print("主板" + Sensor)
        #         if sensor_type == "Fan":
        #             # if Sensor.Value != 0:
        #             device_data[Sensor.Name] = Sensor.Value
        if 'CPU' in hardware_type.upper():
            device_data["CPUInfo"] = hard.Name
            for Sensor in hard.Sensors:
                # print(hard.Name)
                sensor_type = str(Sensor.SensorType)
                if sensor_type == "Load":
                    if Sensor.Name == "CPU Total":
                        device_data["TotalLoad"] = '%.1f' % Sensor.Value
                if sensor_type == "Clock":
                    if "CPU" in Sensor.Name:
                        clock_data[Sensor.Name.replace(" ", "").replace("#", "")] = '%.1f' % Sensor.Value
                        device_data["Clock"] = clock_data
                if sensor_type == "Temperature":
                    if Sensor.Name == "CPU Package":
                        device_data["CPUPackageTemp"] = '%.1f' % Sensor.Value
                    if Sensor.Name == "Core Average":
                        device_data["CoreAverageTemp"] = '%.1f' % Sensor.Value
                    if Sensor.Name == "Core Max":
                        device_data["CoreMaxTemp"] = '%.1f' % Sensor.Value
                if sensor_type == "Voltage":
                    if Sensor.Name == "CPU Core":
                        device_data["CPUVoltage"] = '%.3f' % Sensor.Value
                if sensor_type == "Power":
                    if Sensor.Name == "CPU Cores":
                        device_data["Power"] = '%.2f' % Sensor.Value
        if 'MEMORY' in hardware_type.upper():
            device_data["MemoryInfo"] = hard.Name
            # print(hard.Name)
            for Sensor in hard.Sensors:
                sensor_type = str(Sensor.SensorType)
                if sensor_type == "Load":
                    if Sensor.Name == "Memory":
                        device_data["MemoryLoad"] = '%.1f' % Sensor.Value
                if sensor_type == "Data":
                    if Sensor.Name == "Memory Used":
                        device_data["Used"] = '%.2f' % Sensor.Value
                    if Sensor.Name == "Memory Available":
                        device_data["Free"] = '%.2f' % Sensor.Value
        if 'GPU' in hardware_type.upper():
            device_data["GPUInfo"] = hard.Name
            # print(hard.Name)
            for Sensor in hard.Sensors:
                sensor_type = str(Sensor.SensorType)
                if sensor_type == "Load":
                    if Sensor.Name == "GPU Core":
                        device_data["GPULoad"] = '%.1f' % Sensor.Value
                    if Sensor.Name == "GPU Memory":
                        device_data["GPUMemoryLoad"] = '%.1f' % Sensor.Value
                if sensor_type == "Clock":
                    if Sensor.Name == "GPU Core":
                        device_data["GPUCoreClock"] = '%.1f' % Sensor.Value
                    if Sensor.Name == "GPU Memory":
                        device_data["GPUMemoryClock"] = '%.1f' % Sensor.Value
                if sensor_type == "Temperature":
                    if Sensor.Name == "GPU Core":
                        device_data["Temp"] = '%.1f' % Sensor.Value
                    if Sensor.Name == "GPU Hot Spot":
                        device_data["HotSpotTemp"] = '%.1f' % Sensor.Value
                if sensor_type == "Fan":
                    if Sensor.Name == "GPU":
                        device_data["FanSpeed"] = Sensor.Value
                if sensor_type == "Control":
                    if Sensor.Name == "GPU Fan":
                        device_data["FanLoad"] = Sensor.Value
        if 'NETWORK' in hardware_type.upper():
            device_data["NetworkInfo"] = hard.Name
            # print(hard.Name)
            for Sensor in hard.Sensors:
                sensor_type = str(Sensor.SensorType)
                if sensor_type == "Throughput":
                    # print("网卡类型" + Sensor.Name)
                    if "Speed" in Sensor.Name:
                        kb = Sensor.Value / 1024
                        if kb < 1024:
                            device_data[Sensor.Name.replace(" ", "")] = '%.1f' % kb + " Kb/s"
                        if kb >= 1024:
                            device_data[Sensor.Name.replace(" ", "")] = '%.1f' % (kb / 1024) + " Mb/s"
        return device_data

    def run(self):
        data_list = []
        type_list = ["CPU", "memory", "GPU"]
        com_len = len(self.computer_tmp.Hardware)
        if com_len > len(type_list):
            number = com_len - len(type_list)
            [type_list.append("Network" + str(i)) for i in range(number)]
        for index in range(com_len):
            device_info = self.params_hardware(index)
            data_list.append({type_list[index]: device_info})
        return data_list


def load_config():
    global wss_url
    wss_url = socket_value


class PostDevicesInfo:
    def __init__(self):
        # path = os.path.dirname(sys.executable)
        # self.device = GetDeviceInfo(path + "\\LibreHardwareMonitorLib")
        self.device = GetDeviceInfo("./LibreHardwareMonitorLib")

    def post_device_info(self):
        global connected
        print("开始发送报文")
        try:
            sio.emit('message', str(json.dumps(self.device.run())), namespace="")
            print("发送报文成功")
        except ConnectionError as e:
            print("发送目标服务器:" + wss_url + " 无法连接...")
            connected = False
            print("重连机制设置完毕")


@sio.on(event='connect')
def connect():
    print('已连接 <=> 服务端')


@sio.on(event='connect_error')
def connect_error():
    global connected
    print('连接服务端报错. 重试中...')
    connected = False
    print("重连机制设置完毕")


@sio.on(event='disconnect')
def disconnect_handler():
    global connected
    print('主动关闭连接服务端. 准备重试中...')
    connected = False
    print("重连机制设置完毕")


def connect_to_server():
    global connected
    try:
        print('开始连接：客户端 => 服务端')
        sio.connect(wss_url)
        sio.emit("exe", "桌面客户端")
        print('连接成功：客户端 <=> 服务端')
        connected = True
    except Exception as e:
        print(f"连接失败：客户端 =/= 服务端 {e}")
        connected = False


info = PostDevicesInfo()
# # 程序入口
if __name__ == '__main__':
    load_config()
    print(f"socket上报地址： {wss_url}")
    print("Monitor启动成功：")
    while True:
        while not connected:
            connect_to_server()
            print("连接完成，准备启动上报程序")
        info.post_device_info()
        time.sleep(1)
        continue
